package ws

import (
	"context"
	"device-admin/config/redis"
	"device-admin/internal/app/grpc/protoc/devicec"
	"device-admin/internal/app/grpc/service/device"
	"device-admin/internal/define"
	"encoding/json"
	"io"
	"log"
	"strings"
	"time"

	"192.168.1.75/go-pkg/logx"
	gredis "github.com/go-redis/redis/v8"
	"github.com/gorilla/websocket"
	"google.golang.org/protobuf/proto"
)

// ChatHandle 实时对讲处理
// 订阅指定设备的聊天请求，如果收到97终端聊天请求，则通知前端，
// web前端确定接入,则进入通话过程，并通知97终端
// 接收97终端的消息，转发给web前端
// 如果收到97终止通知的请求，或聊天2分钟内无内容，则前端直接终止聊天，并通知97终端
func ChatHandle(wsConn *websocket.Conn, robotID string) {
	var robotIDs []string
	var pubsub *gredis.PubSub
	lastestChatTime := time.Now().Unix()
	// 结束连接
	connCtx, connCancel := context.WithCancel(context.Background())
	defer connCancel()

	// 连接断开处理
	wsConn.SetCloseHandler(func(code int, text string) error {
		connCancel()
		return nil
	})

	// 订阅聊天消息
	{
		redisCtx, redisCtxCancel := context.WithTimeout(context.Background(), time.Second*3)
		defer redisCtxCancel()
		pubsub = redis.NewDB().Subscribe(redisCtx, define.RedisRobotChatData+robotID)
	}

	// 延迟关闭订阅
	defer func() {
		logx.Info(context.Background(), "websocket disconnect", logx.String("robot_id", strings.Join(robotIDs, ",")))
		if pubsub != nil {
			pubsub.Close()
		}
	}()

	// 异常恢复
	defer func() {
		if err := recover(); err != nil {
			log.Println("webSocket err", err)
			// 结束连接
			connCancel()
		}
	}()

	// 接收处理（接收前端的消息）
	go func(connCtx context.Context) {
		defer func() {
			if err := recover(); err != nil {
				// 结束连接
				connCancel()
			}
		}()
		for {
			select {
			case <-connCtx.Done():
				return
			default:
				_, message, err := wsConn.ReadMessage()
				// 连接检查
				if err == io.EOF {
					// 结束连接
					connCancel()
				}
				// 消息处理
				if err == nil && len(message) > 0 {
					lastestChatTime = time.Now().Unix()
					chatData := define.ChatData{}
					if err := json.Unmarshal(message, &chatData); err == nil {
						msgName := ""
						msgContent := []byte{}
						switch chatData.Type {
						// 启动聊天响应
						case define.ChatType_StartChatRsp:
							startChatRsp := &devicec.StartChatRsp{}
							msgName = string(startChatRsp.ProtoReflect().Descriptor().FullName())
						// 聊天的文本内容
						case define.ChatType_ChatContent:
							if chatData.Text != "" {
								chatContent := &devicec.ChatContent{}
								chatContent.Text = chatData.Text
								msgName = string(chatContent.ProtoReflect().Descriptor().FullName())
								msgContent, _ = proto.Marshal(chatContent)
							}
						// 退出聊天请求
						case define.ChatType_QuitChatReq:
							quitChatReq := &devicec.QuitChatReq{}
							msgName = string(quitChatReq.ProtoReflect().Descriptor().FullName())
						}
						device.MsgPack(robotID, msgName, msgContent, "", "97")
					}
				}
				// 不活跃超过一分钟，自动退出
				if time.Now().Unix()-lastestChatTime > 60 {
					connCancel()
					return
				}
				time.Sleep(time.Millisecond * 100)
			}
		}
	}(connCtx)

	// 发送处理（发送消息到前端）
	for {
		// pubsub 空判断
		{
			if pubsub == nil {
				select {
				// 连接超时
				case <-connCtx.Done():
					return
				default:
					time.Sleep(time.Millisecond * 100)
				}
				continue
			}
		}

		// 发送消息
		{
			select {
			// 连接超时
			case <-connCtx.Done():
				return
			// 已收到设备信息
			case msg := <-pubsub.Channel():
				payload := msg.Payload
				// 注意，并发写入会异常
				wsConn.WriteMessage(1, []byte(payload))
				lastestChatTime = time.Now().Unix()
			default:
				time.Sleep(time.Millisecond * 100)
			}
		}
	}
}
